package state

import "fmt"

func _closure(i Instruction, vm LuaVM) {
	a, bx := i.ABx()
	a += 1
	vm.LoadProto(bx)
	vm.Replace(a)
}

func call(i Instruction, vm LuaVM) {
	fmt.Println()
	fmt.Println(" > > >  > > > > > > > > >  > > > > > > > > >  > > > > > > > > >  > > > > > >")
	a, b, c := i.ABC()
	a += 1
	nArgs := _pushFuncAndArgs(a, b, vm)

	//debug 信息
	fmt.Printf("_pushFuncAndArgs 之后   ")
	vm.PrintStack()

	vm.Call(nArgs, c-1)

	//debug 信息
	fmt.Printf("vm.Call 之后   ")
	vm.PrintStack()

	_popResults(a, c, vm)

	//debug 信息
	fmt.Printf("_popResults 之后   ")
	vm.PrintStack()

	fmt.Println("< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <")
	fmt.Println()
}

/**
函数返回的时候，这个时候 栈顶已经有返回值
*/
func _popResults(a, c int, vm LuaVM) {
	if c == 1 {

	} else if c > 1 {
		for i := a + c - 2; i >= a; i-- {
			vm.Replace(i)
		}
	} else { //c<=0
		vm.CheckStack(1)
		vm.PushInteger(int64(a)) //把 a 放到栈顶做个标记
	}
}

func _pushFuncAndArgs(a, b int, vm LuaVM) int {
	if b >= 1 { //b-1 args
		vm.CheckStack(b)
		for i := a; i < a+b; i++ {
			vm.PushValue(i)
		}
		return b - 1
	} else { // b==0 要接收上个函数调用的全部返回值
		_fixStack(a, vm)
		return vm.GetTop() - vm.RegisterCount() - 1
	}
}

func _fixStack(a int, vm LuaVM) {
	x := int(vm.ToInteger(-1))
	vm.Pop(1)
	vm.CheckStack(x - a)
	for i := a; i < x; i++ {
		vm.PushValue(i)
	}
	vm.Rotate(vm.RegisterCount()+1, x-a)
}

/**
把一连串数字推到栈顶
*/
func _return(i Instruction, vm LuaVM) {
	a, b, _ := i.ABC()
	a += 1
	if b == 1 {
		//没有返回值
	} else if b > 1 {
		for i := a; i <= a+b-2; i++ {
			vm.PushValue(i)
		}
	} else { //b==0 ,一部分已经在栈顶了？？？
		_fixStack(a, vm)
	}
}

func vararg(i Instruction, vm LuaVM) {
	a, b, _ := i.ABC()
	a += 1
	if b != 1 {
		vm.LoadVararg(b - 1)
		_popResults(a, b, vm)
	}
}

func tailCall(i Instruction, vm LuaVM) {
	a, b, _ := i.ABC()
	a += 1
	c := 0
	nArgs := _pushFuncAndArgs(a, b, vm)
	vm.Call(nArgs, c-1)
	_popResults(a, c, vm)
}

func self(i Instruction, vm LuaVM) {
	a, b, c := i.ABC()
	a += 1
	b += 1
	vm.Copy(b, a+1)
	vm.GetRK(c)
	vm.GetTable(b)
	vm.Replace(a)
}
